/**
 * 
 */
package org.ranch.model;

import java.util.ArrayList;
import java.util.List;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.JoinColumn;
import javax.persistence.JoinTable;
import javax.persistence.ManyToMany;
import javax.persistence.Table;

/**
 * Represents the user roles in the system
 *
 */
@Entity
@Table(name = "roles")
public class Role extends BaseData implements Comparable<Role> {

    /**
     * default administrator role
     */
    public static final String DEFAULT_ADMIN_ROLE = "ROLE_ADMINISTRATOR";

    private String name;
    private String description;
    private List<Permission> permissions;
    private List<User> users;

    /**
     * default constructor
     */
    public Role() {

    }

    /**
     * constructor with initial specified value
     *
     * @param name
     * @param description
     * @param permissions
     * @param users
     */
    public Role(String name, String description, List<Permission> permissions,
	    List<User> users) {
	super();
	this.name = name;
	this.description = description;
	this.permissions = permissions;
	this.users = users;
    }

    /**
     * @return the name
     */
    @Column(name = "role_name", nullable = false)
    public String getName() {
	return name;
    }

    /**
     * @param name
     *            the name to set
     */
    public void setName(String name) {
	this.name = name;
    }

    /**
     * @return the description
     */
    @Column(name = "description", nullable = false)
    public String getDescription() {
	return description;
    }

    /**
     * @param description
     *            the description to set
     */
    public void setDescription(String description) {
	this.description = description;
    }

    /**
     * @return the permissions
     */
    @ManyToMany
    @JoinTable(name = "role_permissions", joinColumns = @JoinColumn(name = "role_id"), inverseJoinColumns = @JoinColumn(name = "permission_id"))
    public List<Permission> getPermissions() {
	return permissions;
    }

    /**
     * @param permissions
     *            the permissions to set
     */
    public void setPermissions(List<Permission> permissions) {
	this.permissions = permissions;
    }

    /**
     * adds a permission to the role
     *
     * @param permission
     */
    public void addPermission(Permission permission) {
	this.getPermissions().add(permission);
    }

    /**
     * removes a given permission to the role
     *
     * @param permission
     */
    public void removePermission(Permission permission) {
	if (this.getPermissions().contains(permission)) {
	    this.getPermissions().remove(permission);
	}
    }

    /**
     * @return the users
     */
    @ManyToMany(cascade = { CascadeType.PERSIST, CascadeType.MERGE }, mappedBy = "roles", targetEntity = User.class)
    public List<User> getUsers() {
	return users;
    }

    /**
     * @param users
     *            the users to set
     */
    public void setUsers(List<User> users) {
	this.users = users;
    }

    /**
     * adds a given user to the role
     *
     * @param user
     */
    public void addUser(User user) {
	if (users == null) {
	    users = new ArrayList<User>();
	}

	if (user != null) {
	    if (!this.users.contains(user)) {
		users.add(user);
		user.addRole(this);
	    }
	}
    }

    /**
     * removes a given user from the role
     *
     * @param user
     */
    public void removeUser(User user) {
	if (user == null || users == null || users.size() == 0) {
	    return;
	}

	if (this.getUsers().contains(user)) {
	    getUsers().remove(user);
	    user.removeRole(this);
	}
    }

    /**
     * Checks if this role is the default administrator <code>Role</code> that
     * ships with the system
     *
     * @return True only and only if
     *         <code>role.getName().equals(Role.DEFAULT_ADMIN_ROLE);</code>
     */
    public boolean checkIfDefaultAdminRole() {
	return this.getName().equals(Role.DEFAULT_ADMIN_ROLE);
    }

    /*
     * (non-Javadoc)
     *
     * @see java.lang.Object#toString()
     */
    @Override
    public String toString() {
	if (this.getName() != null && this.getName().trim().length() > 0)
	    return this.getName();

	return super.toString();
    }

    @Override
    public int compareTo(Role o) {
	return this.getName().compareToIgnoreCase(o.getName());
    }
}